﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.SharePoint.Administration;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;

namespace UsageFileWorker
{


    public class Reader
    {

        public delegate void UsageEntryAddedHandler(SPUsageEntry e);
        public event UsageEntryAddedHandler UsageEntryAdded;


        public static BinaryFormatter formatter = new BinaryFormatter();


        public void ReadUsageLogFile(FileInfo logFileInfo)
        {
            if (logFileInfo == null)
            {
                throw new ArgumentNullException("logFileInfo");
            }

            Debug.WriteLine(string.Format("Importing usage log file: '{0}'.", new object[] { logFileInfo.FullName }));
            TraceSessionHandle traceHandle = null;
            try
            {
                Debug.WriteLine(string.Format("Openning trace session to usage log file: '{0}'.", new object[] { logFileInfo.FullName }));
                NativeMethods.EventCallback eventCallback = new NativeMethods.EventCallback(this.UsageEventCallback);
                traceHandle = TraceSessionHandle.OpenTrace(logFileInfo.FullName, eventCallback);
                if (!TraceSessionHandle.IsNullOrInvalid(traceHandle))
                {
                    Debug.WriteLine(string.Format("Processing trace session to usage log file: '{0}'.", new object[] { logFileInfo.FullName }));
                    TraceSessionHandle.ProcessTrace(traceHandle);
                }
                else
                {
                    Debug.WriteLine(string.Format("Skipped processing of usage log file (invalid handle): '{0}'.", new object[] { logFileInfo.FullName }));
                }
                GC.KeepAlive(eventCallback);
            }
            finally
            {
                if (!TraceSessionHandle.IsNullOrInvalid(traceHandle))
                {
                    Debug.WriteLine(string.Format("Closing trace session to usage log file: '{0}'.", new object[] { logFileInfo.FullName }));
                    traceHandle.Dispose();
                }
            }
            Debug.WriteLine(string.Format("Imported usage log file: '{0}'.", new object[] { logFileInfo.FullName }));
        }




        internal unsafe void UsageEventCallback(ref NativeMethods.EVENT_TRACE pEvent)
        {
            try
            {
                if ((pEvent.MofLength > 0) && (pEvent.Header.Guid != NativeMethods.EventTraceGuid))
                {
                    SPUsageEntry entry = null;
                    UnmanagedMemoryStream serializationStream = new UnmanagedMemoryStream((byte*)pEvent.MofData, (long)pEvent.MofLength, (long)pEvent.MofLength, FileAccess.Read);
                    try
                    {
                        entry = formatter.Deserialize(serializationStream) as SPUsageEntry;
                        UsageEntryAdded(entry);
                    }
                    catch (Exception exception)
                    {
                        //TODO: Log this
                        Debug.WriteLine(string.Format("Error: {0}", exception));
                    }
                    finally
                    {
                        if (serializationStream != null)
                        {
                            serializationStream.Dispose();
                        }
                    }
                }
            }
            catch (Exception exception2)
            {
                //TODO: Log this
                Debug.WriteLine(string.Format("Error: {0}", exception2));
            }
        }

        private string FormatEntry(SPUsageEntry entry)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(entry.CorrelationId);
            sb.Append(", ");
            sb.Append(entry.FarmId);
            sb.Append(", ");
            sb.Append(entry.MachineName);
            sb.Append(", ");
            sb.Append(entry.ParentType);
            sb.Append(", ");
            sb.Append(entry.ParentTypeGuid);
            sb.Append(", ");
            sb.Append(entry.SiteSubscriptionId);
            sb.Append(", ");
            sb.Append(entry.Timestamp);
            sb.Append(", ");
            sb.Append(entry.TimestampUtc);
            sb.Append(", ");
            sb.Append(entry.User);

            if (entry is SPTimerJobUsageEntry)
            {
                SPTimerJobUsageEntry tjue = (SPTimerJobUsageEntry)entry;
                sb.Append(tjue.Duration);
                sb.Append(", ");
                sb.Append(tjue.JobId);
                sb.Append(", ");
                sb.Append(tjue.JobTitle);
                sb.Append(", ");
                sb.Append(tjue.QueryCount);
                sb.Append(", ");
                sb.Append(tjue.QueryDurationSum);
                sb.Append(", ");
                sb.Append(tjue.RequestCount);
                sb.Append(", ");
                sb.Append(tjue.ServerId);
                sb.Append(", ");
                sb.Append(tjue.ServiceCallCount);
                sb.Append(", ");
                sb.Append(tjue.ServiceCallDurationSum);
                sb.Append(", ");
                sb.Append(tjue.ServiceId);
                sb.Append(", ");
                sb.Append(tjue.StartTime);
                sb.Append(", ");
                sb.Append(tjue.EndTime);
                sb.Append(", ");
                sb.Append(tjue.Status);
                sb.Append(", ");
                sb.Append(tjue.WebApplicationId);
                sb.Append(", ");
                sb.Append(tjue.WebApplicationName);
                sb.Append(", ");
            }


            return sb.ToString();
        }


    }
}
